MAKEFLAGS:= -s	# 不显示详细的编译过程

SRC_DIR?=.
__ENTRY_=loader
# __ENTRY_=_start
BULDDIR:=build
NDK_DIR?=/opt/ndk/android-ndk-r27c
NDK_BIN?=${NDK_DIR}/toolchains/llvm/prebuilt/linux-x86_64/bin

BIN_AMD_64      =$(BULDDIR)/proot-loader-amd64
BIN_AMD_32      =$(BULDDIR)/proot-loader-amd32
BIN_ARM_64      =$(BULDDIR)/proot-loader-arm64
BIN_ARM_32      =$(BULDDIR)/proot-loader-arm32

PROOT_VERBOSE	= 0
LOADERVERBOSE	= 4
BUILD_TARGETS	= 
BUILD_TARGETS	+= $(BIN_ARM_64) $(BIN_ARM_32) 
BUILD_TARGETS	+= $(BIN_AMD_64) $(BIN_AMD_32)
# BUILD_TARGETS	= $(BIN_ARM_64)

$(shell mkdir -p $(BULDDIR)	2>/dev/null)

define setup_compiler_gcc
	command -v $(_CMD_CC) >/dev/null ||	(echo "正在安装 $(_PKG_CC)"; sudo apt install -y $(_PKG_CC))
endef

define setup_musl
	if [ ! -d ./musl-libc/usr/include/$(_MuslNam) ]; then									\
		[ -d ./musl-libc ] || mkdir -p ./musl-libc;											\
		echo "正在下载 $(_MuslNam)";														\
		[ -f ./musl-libc/musl-$(_TARGET).deb ] ||											\
		wget -q -O ./musl-libc/musl-$(_TARGET).deb $(_MuslUrl);								\
		echo "正在安装 $(_MuslNam)";														\
		dpkg-deb -x ./musl-libc/musl-$(_TARGET).deb ./musl-libc;							\
		sed -i "s#/usr#./musl-libc/usr#g" ./musl-libc/usr/lib/$(_MuslNam)/musl-gcc.specs;	\
		sed -i "s#__bswap32(__x)+0ULL<<32#(__bswap32(__x)+0ULL)<<32#g"						\
		./musl-libc/usr/include/$(_MuslNam)/endian.h;										\
	fi

endef

define compile_loader_tmx_nostdlib
	echo -e "\n正在编译 $(1) $(0)"

	# 编译
	/home/lenovo/.termux-build/_cache/android-r27c-api-26-v1/bin/clang \
	-target $(_TARGET_NDK) \
	-D_TARGET=\"$(_TARGET)\" \
	$(SRC_DIR)/loader.c \
	-D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -fstack-protector-strong -Oz -Wall -Wextra -O2 -fPIC -ffreestanding \
	-c -o $(1).o

	if [ -f $(SRC_DIR)/assembly.S ]; then \
	/home/lenovo/.termux-build/_cache/android-r27c-api-26-v1/bin/clang \
	-target $(_TARGET_NDK) \
	-D_TARGET=\"$(_TARGET)\" \
	$(SRC_DIR)/assembly.S \
	-D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -fstack-protector-strong -Oz -Wall -Wextra -O2 -fPIC -ffreestanding \
	-c -o $(1).S.o \
	; \
	fi

	# 链接
	/home/lenovo/.termux-build/_cache/android-r27c-api-26-v1/bin/clang \
	-target $(_TARGET_NDK) \
	-static -nostdlib \
	$(1).o `if [ -f $(1).S.o ]; then echo "$(1).S.o"; fi` \
	-Wl,--build-id=none,-Ttext=$(LOADER_ADDRESS),-z,noexecstack \
	-Os -ffunction-sections -fdata-sections -fvisibility=hidden -Wl,--gc-sections,-e$(__ENTRY_) -o $(1)

	# /home/lenovo/.termux-build/_cache/android-r27c-api-26-v1/bin/clang \
	# -target $(_TARGET_NDK) \
	# -D_TARGET=\"$(_TARGET)\" \
	# $(SRC_DIR)/loader.c \
	# -nostdlib \
	# -static -Os -s -ffunction-sections -fdata-sections -fvisibility=hidden -Wl,--gc-sections,-e$(__ENTRY_) -o $(1)
endef

define compile_loader_ndk_nostdlib
	echo -e "\n正在编译 $(1) $(0)"

	# 编译
	/opt/ndk/android-ndk-r27c/toolchains/llvm/prebuilt/linux-x86_64/bin/clang \
	-target $(_TARGET_NDK) \
	-D_TARGET=\"$(_TARGET)\" \
	$(SRC_DIR)/loader.c \
	-D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -fstack-protector-strong -Oz -Wall -Wextra -O2 -fPIC -ffreestanding \
	-c -o $(1).o

	if [ -f $(SRC_DIR)/assembly.S ]; then \
	/opt/ndk/android-ndk-r27c/toolchains/llvm/prebuilt/linux-x86_64/bin/clang \
	-target $(_TARGET_NDK) \
	-D_TARGET=\"$(_TARGET)\" \
	$(SRC_DIR)/assembly.S \
	-D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -fstack-protector-strong -Oz -Wall -Wextra -O2 -fPIC -ffreestanding \
	-c -o $(1).S.o \
	; \
	fi

	# 链接
	/opt/ndk/android-ndk-r27c/toolchains/llvm/prebuilt/linux-x86_64/bin/clang \
	-target $(_TARGET_NDK) \
	-static -nostdlib \
	$(1).o `if [ -f $(1).S.o ]; then echo "$(1).S.o"; fi` \
	-Wl,--build-id=none,-Ttext=$(LOADER_ADDRESS),-z,noexecstack \
	-Os -ffunction-sections -fdata-sections -fvisibility=hidden -Wl,--gc-sections,-e$(__ENTRY_) -o $(1)

	# /opt/ndk/android-ndk-r27c/toolchains/llvm/prebuilt/linux-x86_64/bin/clang \
	# -target $(_TARGET_NDK) \
	# -D_TARGET=\"$(_TARGET)\" \
	# $(SRC_DIR)/loader.c \
	# -nostdlib \
	# -static -Os -s -ffunction-sections -fdata-sections -fvisibility=hidden -Wl,--gc-sections,-e$(__ENTRY_) -o $(1)
endef

define compile_loader_ndk
	# musl-arm32 中 vfprintf 用到浮点运算，这浮点运算的代码在 gcc 内建库中, 而ndk-clang 没有这部分代码，所以无法链接

	echo -e "\n正在编译 $(1) $(0)"
	/opt/ndk/android-ndk-r27c/toolchains/llvm/prebuilt/linux-x86_64/bin/clang \
	-target $(_TARGET_NDK) \
	-D_TARGET=\"$(_TARGET)\" \
	-nostdlib \
	-I./musl-libc/usr/include/$(_MuslNam) \
	-L./musl-libc/usr/lib/$(_MuslNam) \
	-Wl,-Bstatic -lc \
	./musl-libc/usr/lib/$(_MuslNam)/crt1.o \
	./musl-libc/usr/lib/$(_MuslNam)/crti.o \
	$(SRC_DIR)/loader.c \
	./musl-libc/usr/lib/$(_MuslNam)/crtn.o \
	-Wl,--start-group -lc -Wl,--end-group \
	-Wl,--wrap=vfprintf \
	-Wl,--wrap=__aeabi_uidiv \
	-Wl,--build-id=none,-Ttext=$(LOADER_ADDRESS),-z,noexecstack  -v \
	-static -Os -s -ffunction-sections -fdata-sections -fvisibility=hidden -Wl,--gc-sections,-e$(__ENTRY_) -o $(1)

	# 备用
	# -static -Os -s -ffunction-sections -fdata-sections -fvisibility=hidden -Wl,--gc-sections,-e$(__ENTRY_) -o $(1)

	# 备用
	# -static -Os -s -ffunction-sections -fdata-sections -fvisibility=hidden -Wl,--gc-sections -o $(1)

	# 备用
	# -Wl,--build-id=none,-Ttext=$(LOADER_ADDRESS),-z,now \

endef

define compile_loader_gcc
	$(setup_compiler_gcc)

	echo -e "\n正在编译 $(1) $(0)"
	$(_CMD_CC) \
	-D_TARGET=\"$(_TARGET)\" \
	$(SRC_DIR)/loader.c -static -Os -s -ffunction-sections -fdata-sections -fvisibility=hidden -Wl,--gc-sections,-e$(__ENTRY_)  -o $(1)\
	-Wl,--build-id=none,-Ttext=$(LOADER_ADDRESS),-z,noexecstack \
	-specs ./musl-libc/usr/lib/$(_MuslNam)/musl-gcc.specs

	#  -s
	# -Wl,--build-id=none,-Ttext=$(LOADER_ADDRESS),-z,now \

endef

define compile_demoxx_ndk
	echo -e "\n正在编译 $(1) $(0)"

	echo "#include <stdio.h>"												> $(BULDDIR)/demo.c
	echo "int main(int argc, char** argv) { printf(\"运行成功了\\n\"); }"	>>$(BULDDIR)/demo.c

	/opt/ndk/android-ndk-r27c/toolchains/llvm/prebuilt/linux-x86_64/bin/clang \
	-target $(_TARGET_NDK) \
	$(BULDDIR)/demo.c -o $(1)

	# /opt/ndk/android-ndk-r27c/toolchains/llvm/prebuilt/linux-x86_64/bin/clang \
	# -target $(_TARGET_NDK) \
	# -nostdlib \
	# -I./musl-libc/usr/include/$(_MuslNam) \
	# -L./musl-libc/usr/lib/$(_MuslNam) \
	# -Wl,-Bstatic -lc \
	# ./musl-libc/usr/lib/$(_MuslNam)/crt1.o \
	# ./musl-libc/usr/lib/$(_MuslNam)/crti.o \
	# $(BULDDIR)/demo.c \
	# ./musl-libc/usr/lib/$(_MuslNam)/crtn.o \
	# -Wl,--start-group -lc -Wl,--end-group \
	# -Wl,--wrap=vfprintf \
	# -Wl,--wrap=__aeabi_uidiv \
	# -static -Os -s -ffunction-sections -fdata-sections -fvisibility=hidden -Wl,--gc-sections -o $(1)

endef

define compile
	# $ (call compile_loader_gcc,$(1))
	# $ (call compile_loader_ndk_nostdlib,$(1))
	# $ (call compile_loader_tmx_nostdlib,$(1))
	$(call compile_loader_ndk,$(1))
	$(call compile_demoxx_ndk,$(1).demo)
endef


all: default

main_zig:
	echo "const std = @import(\"std\");"
	echo "const linux = std.os.linux;"
	echo ""
	echo "fn test1() void {"
	echo "    std.debug.print(\"Hello from test1!\\n\", .{});"
	echo "}"
	echo ""
	echo "pub fn main() void {"
	echo "    // while(true) {_=undefined;}"
	echo "    std.debug.print(\"Hello from main!\\n\", .{});"
	echo "    test1();"
	echo "    linux.exit(99); // 系统调用退出"
	echo "}"
	echo ""

zig1: # 编译太慢了。。。
	make main_zig>$(BULDDIR)/main.zig
	zig build-exe $(BULDDIR)/main.zig -static -O ReleaseFast -fstrip   \
    -lc -target aarch64-linux-musl \
    -isystem /usr/include/aarch64-linux-musl \
    -L /usr/lib/aarch64-linux-musl

	# 测试运行也成功
	adb push ../../../../../ex_ndk_tools/arm64/ndkproot/proot /data/local/tmp/proot
	adb push main /data/local/tmp/proot_loader64 >/dev/null 2>&1
	adb shell env PROOT_TMP_DIR=/data/local/tmp PROOT_LOADER=/data/local/tmp/proot_loader64 PROOT_VERBOSE=$(PROOT_VERBOSE) LOADERVERBOSE=$(LOADERVERBOSE)  /data/local/tmp/proot /system/bin/ls -al

zig2: # 编译太慢了。。。
	make main_zig>$(BULDDIR)/main.zig
	zig build-exe $(BULDDIR)/main.zig -static -O ReleaseFast -fstrip  \
    -lc -target x86_64-linux-musl \
    -isystem /usr/include/x86_64-linux-musl \
    -L /usr/lib/x86_64-linux-musl

	# 测试运行也成功
	PROOT_LOADER=./main LOADERVERBOSE=$(LOADERVERBOSE) proot /bin/ls -al


#######################################


musl_uninstall:
	for item in \
		arm-linux-musleabihf \
		aarch64-linux-musl \
		i386-linux-musl \
		x86_64-linux-musl \
	; do \
		echo "正在卸载 musl libc 库: $$item"; \
		sudo rm -rf /usr/include/$$item   /usr/lib/$$item; \
	done;

	rm -rf ./musl-libc

#######################################


$(BIN_ARM_64): $(SRC_DIR)/loader.c
	$(eval _TARGET:=aarch64)
	$(eval _CMD_CC:=    aarch64-linux-gnu-gcc)
	$(eval _PKG_CC:=gcc-aarch64-linux-gnu)
	$(eval _MuslNam:=   aarch64-linux-musl)
	$(eval _MuslUrl:=https://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/pool/universe/m/musl/musl-dev_1.2.5-3_arm64.deb)
	$(eval LOADER_ADDRESS=0x2000000000)
	$(eval _TARGET_NDK:=aarch64-none-linux-android26)

	$(setup_musl)
	$(call compile,$@)

	echo "正在生成 loader-info.c (编译proot时用到)"
	adb disconnect
	adb connect 192.168.1.56:1111
	adb push $@ /data/local/tmp/loader
	adb shell /data/local/tmp/loader geninfo 2>&1 |tee $(BULDDIR)/loader-info.c
	sed -i "s#\[loader\] ##g"  $(BULDDIR)/loader-info.c

	# echo "正在生成 loader-info.c (编译proot时用到)"
	# echo "#include <unistd.h>"																	> $(BULDDIR)/loader-info.c
	# echo ""																						>>$(BULDDIR)/loader-info.c
	# echo "#define _ptr_end   0x`readelf -s $@|grep pokedata_workaround|awk '{print $$2}'`;"		>>$(BULDDIR)/loader-info.c
	# echo "#define _ptr_start 0x`readelf -s $@|grep loader|grep FUNC   |awk '{print $$2}'`;"		>>$(BULDDIR)/loader-info.c
	# echo "const ssize_t offset_to_pokedata_workaround=_ptr_end - _ptr_start;"						>>$(BULDDIR)/loader-info.c

	# echo "正在转成 loader-wrapped.o (编译proot时用到,除非定义了 PROOT_UNBUNDLE_LOADER 宏)"
	# llvm-objcopy --input-target=binary \
	# --output-target="`llvm-objdump -f $@|grep 'file format'|awk '{print $$4}'`" \
	# --binary-architecture="`llvm-objdump -f $@|grep 'architecture'|awk '{print $$2}'`" \
	# $@  $(BULDDIR)/loader-wrapped.o

$(BIN_ARM_32): $(SRC_DIR)/loader.c
	$(eval _TARGET:=arm)
	$(eval _CMD_CC:=arm-linux-gnueabihf-gcc)
	$(eval _PKG_CC:=gcc-arm-linux-gnueabihf)
	$(eval _MuslNam:=arm-linux-musleabihf)
	$(eval _MuslUrl:=https://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/pool/universe/m/musl/musl-dev_1.2.5-3_armhf.deb)
	$(eval LOADER_ADDRESS=0x20000000)
	$(eval _TARGET_NDK:=armv7a-none-linux-android26)

	$(setup_musl)
	$(call compile,$@)

$(BIN_AMD_64): $(SRC_DIR)/loader.c
	$(eval _TARGET:=x86_64)
	$(eval _CMD_CC:=    x86_64-linux-gnu-gcc)
	$(eval _PKG_CC:=gcc-x86_64-linux-gnu)
	$(eval _MuslNam:=   x86_64-linux-musl)
	$(eval _MuslUrl:=https://mirrors.tuna.tsinghua.edu.cn/ubuntu/pool/universe/m/musl/musl-dev_1.2.5-3_amd64.deb)
	$(eval LOADER_ADDRESS=0x600000000000)
	$(eval _TARGET_NDK:=x86_64-none-linux-android26)

	$(setup_musl)
	$(call compile,$@)

$(BIN_AMD_32): $(SRC_DIR)/loader.c
	$(eval _TARGET:=i386)
	$(eval _MuslNam:=   i386-linux-musl)
	$(eval _MuslUrl:=https://mirrors.tuna.tsinghua.edu.cn/ubuntu/pool/universe/m/musl/musl-dev_1.1.9-1_i386.deb)
	$(eval LOADER_ADDRESS=0xa0000000)
	$(eval _TARGET_NDK:=i686-none-linux-android26)

	# /usr/lib/i386-linux-musl/musl-gcc.specs 在这里:
	[ -f        ./musl-libc/musl-$(_TARGET)_specs.deb ] || \
	wget -q -O  ./musl-libc/musl-$(_TARGET)_specs.deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/pool/universe/m/musl/musl-tools_1.1.19-1_i386.deb
	dpkg-deb -x ./musl-libc/musl-$(_TARGET)_specs.deb ./musl-libc

	$(setup_musl)
	$(call compile,$@)

#######################################


c: $(BUILD_TARGETS)
	@echo 体积：
	@ls -Al $(BULDDIR)/
	@echo

u:c
	cp -f $(BIN_ARM_32)  ../../cli_droid/assets_as_library/arm64-v8a/pr-loader32
	cp -f $(BIN_ARM_64)  ../../cli_droid/assets_as_library/arm64-v8a/pr-loader64


#######################################


define test_run_armXX
	echo -e "\n正在通过adb连接安卓设备"
	adb disconnect
	adb connect 192.168.1.56:1111

	echo -e "\n正在测试 $(1)"
	adb push ../../../../../ex_ndk_tools/arm64/ndkproot/proot	/data/local/tmp/proot_
	adb push $(1)												/data/local/tmp/loader	>/dev/null 2>&1
	adb push $(1).demo											/data/local/tmp/demoxx	>/dev/null 2>&1

	# echo "正在直接运行 loader(不通过proot)"
	# adb shell /data/local/tmp/loader

	echo "正在使用 proot 加载 $(1)"
	# adb push /mnt/c/Users/lenovo/Desktop/test/loader/lib_pr-loader32.so  /data/local/tmp/loader	>/dev/null 2>&1 # 原版loader
	$(eval tmpcmd=adb shell "(cd /data/local/tmp && PROOT_VERBOSE=$(PROOT_VERBOSE) LOADERVERBOSE=$(LOADERVERBOSE) PROOT_TMP_DIR=./ PROOT_LOADER=./loader PROOT_LOADER_32=./loader ./proot_ ./demoxx)")
	echo '$(tmpcmd)'; echo ""
	$(tmpcmd)

	# /system/bin/ls -Al
endef

define test_run_amdXX
	echo -e "amd32/amd64 两个版本的测试环境需要安装 x86-android 环境, 比如：木木模拟器, 等等"
	echo "模拟器的adbd要允许远程连接, 连接指令如下:"
	echo "adb connect 192.168.1.5:7555"

	echo -e "\n正在通过adb连接安卓设备"
	adb disconnect
	adb connect 192.168.1.5:7555

	echo -e "\n正在测试 $(1)"
	adb push /mnt/c/Users/lenovo/Desktop/test/proot/proot		/data/local/tmp/proot_	>/dev/null 2>&1
	adb push $(1)										/data/local/tmp/loader	>/dev/null 2>&1
	adb push $(1).demo									/data/local/tmp/demoxx	>/dev/null 2>&1

	# echo "正在直接运行 loader(不通过proot)"
	# adb shell /data/local/tmp/loader

	echo "正在使用 proot 加载 $(1)"
	# adb push /mnt/c/Users/lenovo/Desktop/test/proot/loader/loader32		/data/local/tmp/loader	>/dev/null 2>&1 # 原版loader
	$(eval tmpcmd=adb shell "(cd /data/local/tmp && PROOT_VERBOSE=$(PROOT_VERBOSE) LOADERVERBOSE=$(LOADERVERBOSE) PROOT_TMP_DIR=./ PROOT_LOADER=./loader PROOT_LOADER_32=./loader ./proot_ ./demoxx)")
	echo '$(tmpcmd)'; echo ""
	$(tmpcmd)

	# /system/bin/ls -Al
endef

define test_run_amdXX_inWsl
	echo -e "\n正在测试 $(1)"

	# echo -e "正在直接运行 loader(不通过proot)\n\n"
	# $(1)

	echo -e "正在使用proot加载 $(1)\n\n"
	PROOT_TMP_DIR=/tmp \
	PROOT_LOADER=$(1) \
	PROOT_LOADER_32=$(1) \
	PROOT_VERBOSE=$(PROOT_VERBOSE) \
	LOADERVERBOSE=$(LOADERVERBOSE) \
	proot \
	ls -Al

	# $(1).demo
endef

d1:$(BIN_ARM_64)
	$(call test_run_armXX,${BIN_ARM_64})

d2:$(BIN_ARM_32)
	$(call test_run_armXX,${BIN_ARM_32})

d3:$(BIN_AMD_64)
	$(call test_run_amdXX,${BIN_AMD_64})

d4:$(BIN_AMD_32)
	$(call test_run_amdXX,${BIN_AMD_32})


#######################################


default:d3
	#do nothing

clean: 
	rm -rf $(BULDDIR) *.d *.o a.out main

